package vn.qnamuni.calendar.providers;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import vn.qnamuni.calendar.alarm.AlarmHelper;
import vn.qnamuni.calendar.constants.PersonContract;
import vn.qnamuni.calendar.db.MyDatabaseHelper;
import vn.qnamuni.calendar.db.PersonTable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class MyContentProvider extends ContentProvider {

	// database
	private MyDatabaseHelper database;

	// Used for the UriMacher
	private static final int CONTACTS = 10;
	private static final int ITEM = 20;

	public static final String AUTHORITY = "vn.qnamuni.calendar.providers";

	private static final String BASE_PATH = PersonTable.TABLE_CONTACTS;
	public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
			+ "/" + BASE_PATH);

	public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE
			+ "/contact";
	public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
			+ "/item";

	private static final UriMatcher sURIMatcher = new UriMatcher(
			UriMatcher.NO_MATCH);
	static {
		sURIMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
		sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", ITEM);
	}

	@Override
	public boolean onCreate() {
		database = new MyDatabaseHelper(getContext());
		return false;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		int rowsDeleted = 0;
		switch (uriType) {
		case CONTACTS:
			rowsDeleted = sqlDB.delete(PersonTable.TABLE_CONTACTS, selection,
					selectionArgs);
			break;
		case ITEM:
			String id = uri.getLastPathSegment();
			if (TextUtils.isEmpty(selection)) {
				rowsDeleted = sqlDB.delete(PersonTable.TABLE_CONTACTS,
						PersonContract.Entry.KEY_ID + "=" + id, null);
			} else {
				rowsDeleted = sqlDB.delete(PersonTable.TABLE_CONTACTS,
						PersonContract.Entry.KEY_ID + "=" + id + " and "
								+ selection, selectionArgs);
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return rowsDeleted;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		long id = 0;
		switch (uriType) {
		case CONTACTS:
			try {
				id = sqlDB.insertOrThrow(PersonTable.TABLE_CONTACTS, null,
						values);
				if (id > 0) {
					getContext().getContentResolver().notifyChange(uri, null);
					return Uri.parse(BASE_PATH + "/" + id);
				} else {
					throw new SQLException("Failed to insert row into " + uri); //thêm thất bại
				}
			} catch (SQLiteConstraintException e) {
				Log.i("INSERT DATABASE", "Ignoring constraint failure."); //bỏ qua hạn chế
				Log.v("SQL insert", e.getMessage());
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri); //ko xác định đc uri
		}

		return null;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// sử dụng SQLiteQueryBuilder thay vì phương thức query()
		SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

		// kiểm tra sự tồn tại của cột mà người dùng gọi
		checkColumns(projection);

		// thiết lập bảng
		queryBuilder.setTables(PersonTable.TABLE_CONTACTS);

		int uriType = sURIMatcher.match(uri);
		switch (uriType) {
		case CONTACTS:
			break;
		case ITEM:
			// Thêm ID với truy vấn ban đầu
			queryBuilder.appendWhere(PersonContract.Entry.KEY_ID + "="
					+ uri.getLastPathSegment());
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		SQLiteDatabase db = database.getWritableDatabase();
		Cursor cursor = queryBuilder.query(db, projection, selection,
				selectionArgs, null, null, sortOrder);

		// Make sure that potential listeners are getting notified
		cursor.setNotificationUri(getContext().getContentResolver(), uri);

		return cursor;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int uriType = sURIMatcher.match(uri);
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		int rowsUpdated = 0;
		switch (uriType) {
		case CONTACTS:
			rowsUpdated = sqlDB.update(PersonTable.TABLE_CONTACTS, values,
					selection, selectionArgs);
			break;
		case ITEM:
			String id = uri.getLastPathSegment();
			if (TextUtils.isEmpty(selection)) {
				rowsUpdated = sqlDB.update(PersonTable.TABLE_CONTACTS, values,
						PersonContract.Entry.KEY_ID + "=" + id, null);
			} else {
				rowsUpdated = sqlDB.update(PersonTable.TABLE_CONTACTS, values,
						PersonContract.Entry.KEY_ID + "=" + id + " and "
								+ selection, selectionArgs);
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return rowsUpdated;
	}

	@Override
	public int bulkInsert(Uri uri, ContentValues[] values) {
		// TODO Auto-generated method stub
		// get writable
		SQLiteDatabase sqlDB = database.getWritableDatabase();
		Set<Integer> setIDList = new HashSet<Integer>();
		// begin
		sqlDB.beginTransaction();
//		delete(uri, null, null);
		try {
			String[] projection = { PersonContract.Entry.KEY_ID,
					PersonContract.Entry.KEY_UID,
					PersonContract.Entry.KEY_DATE };

			Set<String> nonDelUIDList = new HashSet<String>();
			Set<String> uidLst = new HashSet<String>();

			// event id = null => set new
			String[] p1 = { PersonContract.Entry.KEY_UID };
			Cursor c1 = query(CONTENT_URI, p1, null, null, null);
			c1.moveToFirst();
			
			Log.v("bulkInsert", "1");
			int i = c1.getCount();
			while (i > 0) {
				--i;
				uidLst.add(c1.getString(0));
				c1.moveToNext();
			}
			Log.v("bulkInsert", "2");
			for (ContentValues v : values) {
				// v contain maximum new 4 attrs

				// * query uid if non exist => insert if exist => update, if
				// * update name and date => add to list id

				String uid = v.getAsString(PersonContract.Entry.KEY_UID);
				// add uid to list non-delete
				nonDelUIDList.add(uid);

				if (!uidLst.contains(uid)) {
					Uri ui = insert(CONTENT_URI, v);
					int id = Integer.valueOf(ui.getLastPathSegment());
					setIDList.add(id);
				} else {
					
					//waste time
					Cursor c = query(CONTENT_URI, projection,
							PersonContract.Entry.KEY_UID + " LIKE ?",
							new String[] { "%" + uid + "%" }, null);
					c.moveToFirst();
					int id = c.getInt(0);
					String oldDate = c.getString(2);
					update(CONTENT_URI, v, PersonContract.Entry.KEY_ID
							+ " LIKE ?",
							new String[] { "%" + String.valueOf(id) + "%" });
					String newDate = v
							.getAsString(PersonContract.Entry.KEY_DATE);

					Log.v("old and new", oldDate + " " + newDate);
					if (!newDate.equals(oldDate)) {
						setIDList.add(id);
					}
					
				}
			}
			// keep local: uid = 'LOCAL'
			nonDelUIDList.add("LOCAL");
			// clear database

			StringBuilder wordSet = new StringBuilder();
			for (String word : nonDelUIDList) {
				if (wordSet.length() > 1)
					wordSet.append(',');
				wordSet.append("'" + word + "'");
			}
			delete(CONTENT_URI, PersonContract.Entry.KEY_UID + " NOT IN ("
					+ wordSet.toString() + ")", null);
			// clear what is not in new database
			// notify success
			sqlDB.setTransactionSuccessful();
			
			//add: setId
			//del: chua dc
			AlarmHelper alarm = AlarmHelper.getInstance();
			if (null != alarm) {
				alarm.addAlarms(setIDList);
			} 
		} catch (Exception e) {
			Log.v("bulkInsert", "exception : " + e.getMessage());
			setIDList.clear();
		} finally {
			sqlDB.endTransaction();
		}

		return 1;
	}

	/**
	 * @param projection
	 *            : this function used to check if column is valid
	 */
	private void checkColumns(String[] projection) {
		if (projection != null) {
			HashSet<String> requestedColumns = new HashSet<String>(
					Arrays.asList(projection));
			HashSet<String> availableColumns = new HashSet<String>(
					Arrays.asList(PersonContract.keySet));
			// Kiểm tra xem tất cả các cột được yêu cầu có sẵn
			if (!availableColumns.containsAll(requestedColumns)) {
				throw new IllegalArgumentException(
						"Unknown columns in projection");
			}
		}
	}
}